﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BingVis.SilverlightClient.Common;
using Microsoft.VisualBasic;
using System.IO;
using System.Text.RegularExpressions;

namespace BingVis.SilverlightClient.GoogleTransit
{
    public class TextFieldParser
    {
        private const int MAX_FIELDS = 500;
        private StringReader _reader;

        public TextFieldParser(StringReader lineReader)
        {
            _reader = lineReader;
        }

        public string[] ReadFields()
        {
            var line = _reader.ReadLine();
            if (!line.Contains(","))
            {
                // No commas, one field.
                return new string[] { line };
            }

            // Migrated from some Java code... thats why it's ugly.
            bool inQuote = false;
            String currField = "";
            int fieldIdx = 0;
            char currChar = ' ';
            var fields = new List<string>();
            try
            {
                for (int i = 0; i < line.Length; i++)
                {
                    currChar = line[i];
                    if (currChar == '"')
                    {
                        if (inQuote)
                        {
                            fields.Add(currField);
                            currField = "";
                            fieldIdx++;
                        }
                        inQuote = !inQuote;
                        continue;
                    }

                    if (currChar == ',' && !inQuote)
                    {
                        if (currField != "")
                        {
                            fields.Add(currField);
                            currField = "";
                            fieldIdx++;
                        }
                        continue;
                    }

                    currField += currChar;
                }

                fields.Add(currField);
            }
            catch(Exception e)
            {
                throw e;
            }

            return fields.ToArray();
        }
    }

    public class CSVParser : ICSVParser
    {
        List<string> _fields;
        int _fieldCount = 0;
        StringReader lineReader;
        TextFieldParser fieldParser;
        bool hasHeader = false;

        public CSVParser(IGTFSFile file)
            : this(file.Lines.First())
        {
            hasHeader = true;
        }

        public CSVParser(string fieldSet)
            : this(fieldSet, false)
        {

        }

        public CSVParser(string fieldSet, bool hasFields)
        {
            _fields = new List<string>();

            foreach (var field in fieldSet.Split(",".ToCharArray()))
            {
                _fields.Add(field.Trim());
            }

            _fieldCount = _fields.Count;

            hasHeader = hasFields;
        }

        #region ICSVParser Members

        public List<ICSVLine> ParseFile(IGTFSFile file)
        {
            return GetLines(file).ToList();
        }

        public IEnumerable<ICSVLine> GetLines(IGTFSFile file)
        {
            var skipCount = hasHeader ? 1 : 0;

            var result = file.Lines
                // Skip the first line.
                .Skip(skipCount)
                // Parse each line
                .Select(line => ParseLine(line))
                .AsEnumerable();

            return result;
        }

        public ICSVLine ParseLine(string line)
        {
            string[] delims = { "," };

            // Quick fix for lines that sometimes are quoted.
            while (Regex.IsMatch(line, @""".+?[^""],.+?"""))
            {                
                // fix the line.
                var matches = Regex.Match(line, @""".+?[^""](?<comma>,).+?""");
                var commaIdx = matches.Groups["comma"].Index;
                // Remove the comma
                line = line.Remove(commaIdx, 1).Insert(commaIdx+1, "_");
            }

            lineReader = new StringReader(line);

            fieldParser = new TextFieldParser(lineReader);
            //fieldParser.TextFieldType = FieldType.Delimited;
            //fieldParser.HasFieldsEnclosedInQuotes = false;
            //fieldParser.Delimiters = delims;           

            var rowVals = fieldParser.ReadFields();
            
            // Combine the fields array and the vals array into a dictionary, keyvaluepairs.
            var valDict = new Dictionary<string, string>();
            if (hasHeader)
            {
                if (rowVals == null || rowVals.Count() != _fieldCount)
                    throw new ArgumentException("Improper number of values for row: { " + rowVals.Count() + ", " + _fieldCount + " }");

                rowVals.Select<string, KeyValuePair<string, string>>(
                    (string currString, int index) => new KeyValuePair<string, string>(_fields[index], currString))
                    // Cheaters way of converting to Dictionary.
                    .ToList()
                    .ForEach(pair => { if (!valDict.ContainsKey(pair.Key)) valDict.Add(pair.Key, pair.Value); });
            }
            else
            {
                List<string> fields = new List<string>();
                foreach (var num in Enumerable.Range(0, rowVals.Count()))
                {
                    fields.Add(num.ToString());
                }

                rowVals.Select<string, KeyValuePair<string, string>>(
                   (string currString, int index) => new KeyValuePair<string, string>(fields[index], currString))
                    // Cheaters way of converting to Dictionary.
                   .ToList()
                   .ForEach(pair => valDict.Add(pair.Key, pair.Value));
            }
            return new CSVLine(valDict);
        }

        #endregion
    }
}
